package CiscoTalkOO;

use strict;
use warnings;

use Expect;
use POSIX qw(strftime);
use Net::Telnet;
use Getopt::Long;
use Proc::ProcessTable;
use Data::Dumper;
use SIM_base;
use SIM_settings;

sub new {
	my $self = {};
	my $object = shift;
	my $ip = shift;
	my $login = shift;
	my $pwd1 = shift;
	my $pwd2 = shift;
	my $preferred_method = shift || "SSHv2";
	$self->{rExp} = undef;
	$self->{IP} = $ip;
	$self->{spawn_ok} = 0;
	$self->{current_connection_method} = "";
	## Connection errors are:
	#	1 = authentication failure (login)
	#	2 = login loops (aka device keeps on asking for username)
	#	3 = authentication failure (after enable)
	#	4 = invalid input detected (only after sending enable command)
	$self->{connection_error} = 0;
	$self->{login} = $login;
	$self->{pwd1} = $pwd1;
	$self->{pwd2} = $pwd2;
	## Methods are:
	#   TELNET
	#   SSHv1
	#   SSHv2
	$self->{prefered_connection_method} = $preferred_method;
	$self->{commands_had_errors} = 0;
	$self->{error_commands} = ();
	$self->{error_lines} = ();
	$self->{connection_method_order} = ();
	$self->{hostname} = "";
	$self->{ssh_key_to_short} = 0;

	bless ($self);
	return $self;
}

sub TelnetPingTest
{
	my $self = shift;
	my $timeout=shift;
	my $repeat=shift;
	my $count=0;
	my $result=0;
	my $debug=0;
	my $t = new Net::Telnet ( Timeout => $timeout, errmode => "return" );

	while ( $result == 0 && $count < $repeat ) {
		if ( ! $t -> open( $self->{IP} ) ) {
			$t -> close;
			$result=0;
		} else {
			$t -> close;
			$result=1;
		}
		$count++;
	}

	return $result;
}


sub StartTalking
{
	my $self = shift;

	my $temp;

	$self->{rExp} = new Expect;
	$self->{rExp}->log_stdout(1);


	if ( $self->{prefered_connection_method} eq "TELNET" ) {
		push @{$self->{connection_method_order}}, "TELNET";
		push @{$self->{connection_method_order}}, "SSHv1";
		push @{$self->{connection_method_order}}, "SSHv2";
	} elsif ( $self->{prefered_connection_method} eq "SSHv1" ) {
		push @{$self->{connection_method_order}}, "SSHv1";
		push @{$self->{connection_method_order}}, "SSHv2";
		push @{$self->{connection_method_order}}, "TELNET";
	} elsif ( $self->{prefered_connection_method} eq "SSHv2" ) {
		push @{$self->{connection_method_order}}, "SSHv2";
		push @{$self->{connection_method_order}}, "SSHv1";
		push @{$self->{connection_method_order}}, "TELNET";
	}

	foreach my $tempmethod (@{$self->{connection_method_order}}) {
		if ( $self->{spawn_ok} == 0 ) {
			print "Trying " . $tempmethod . "\n";
			if ( $tempmethod eq "TELNET" ) { 
				if ( $self->TelnetPingTest( 2, 1 ) == 1 ) {
					$self->{rExp} = undef;
					$self->{rExp} = new Expect;
					$self->connectTelnet();
				} else {
					$self->{spawn_ok} = 0;
					$self->{connection_error} = 0;
				}
			} elsif ( $tempmethod eq "SSHv1" ) {
				$self->{rExp} = undef;
				$self->{rExp} = new Expect;
				$self->connectSSHv1();
			} elsif ( $tempmethod eq "SSHv2" ) {
				$self->{rExp} = undef;
				$self->{rExp} = new Expect;
				$self->connectSSHv2();
			}
		}
	}
	if ( $self->{spawn_ok} == 0 ) {
		$self->{current_connection_method} = "";
	}
}

sub connectTelnet
{
	my $self = shift;

	$self->{rExp}->spawn("telnet " . $self->{IP} . " 2>&1");

	my $user_prompt = '([^ \r\n]*)>';
	my $enable_prompt = '([^ \r\n]*)\#';
	my $config_global_prompt = '([^ \r\n]*).config.\#';
	my $config_line_prompt = '([^ \r\n]*).config-l\[ine]{0,3}.\#';
	my $config_interface_prompt = '([^ \r\n]*).config-(if?|s.*).\#';	
	my $config_acl_prompt = '([^ \r\n]*).config-\[^ \r\n]*\#';
	my $catos_enable_prompt = '([^ \r\n]*)> \(enable\)';

#	my $user_prompt = '>';
#	my $enable_prompt = '[^ \r\n]*\#';
#	my $config_global_prompt = '[^ \r\n]*.config.\#';
#	my $config_line_prompt = '[^ \r\n]*.config-l\[ine]{0,3}.\#';
#	my $config_interface_prompt = '[^ \r\n]*.config-(if?|s.*).\#';	
#	my $config_acl_prompt = '[^ \r\n]*.config-\[^ \r\n]*\#';
#	my $catos_enable_prompt = '[^ \r\n]*> \(enable\)';

	my $spawn_ok=0;
	my $connection_error=0; # 1 = auth fail, 2 = login loop
	my $login_count = 1;
	$self->{current_connection_method} = "TELNET";

	$self->{rExp} -> expect( 15, 
		[ qr/(?i)authentication failed/, 
		sub {
			$spawn_ok = 1;
			$connection_error = 1;
		}
		],

		[ qr/(?i)login\s+failed/,
		sub {
			$spawn_ok = 1;
			$connection_error = 1;
		}
		],

		[ qr/(?i)Failed\s+login/,
		sub {
			$spawn_ok = 1;
			$connection_error = 1;
		}
		],

		[ qr/(?i)connection timed out/,
		sub {
			$spawn_ok = 0;
			$connection_error = 0;
		}
		],

		[ qr/(?i)username:/,
		sub {
			$spawn_ok = 1;
			my $fh = shift;
			$fh -> send($self->{login} . "\n");
			$login_count++;
			if ( $login_count > 5 ) { 
				$connection_error = 2;
			} else {
				exp_continue;
			}
		}
		],

		[ qr/(?i)password:/,
		sub {
			$spawn_ok = 1;
			$connection_error = 0;
			my $fh = shift;
			$fh -> send($self->{pwd1} . "\n");
			exp_continue;
		}
		],

		[ qr/($user_prompt)/,
		sub {
			$spawn_ok = 1;
			$connection_error = 0;
			my $fh = shift;
			$fh -> send("ena\n");
			$self->{hostname} = $fh->matchlist()->[0];
		}
		],

		[ qr/($enable_prompt)|($catos_enable_prompt)/,
		sub {
			$spawn_ok = 1;
			$connection_error = 0;
			my $fh = shift;
			$fh -> send("\n");
			$self->{hostname} = $fh->matchlist()->[0];
		}
		],

		[ qr/(?i)Connection refused/,
		sub {
			$spawn_ok = 0;
		}
		],

		[ qr/(?i)Connect to local/,
		sub {
		        $spawn_ok = 1;
			$connection_error = 0;
			my $fh = shift;
			$fh -> send("local\n");
			exp_continue;
		}
		]
	);

	if ( $connection_error == 0 && $spawn_ok == 1 ) {
		$self->{rExp} -> expect( 15, 
			[ qr/(?i)password:/,
			sub { 
				$spawn_ok = 1;
				my $fh = shift;
				$fh -> send($self->{pwd2}."\n");
			}
			],

			[ qr/(?i)error in authentication/,
			sub { 
				$spawn_ok = 1;
				$connection_error = 3;
			}
			],

			[ qr/(?i)invalid input detected/,
			sub {
				$spawn_ok = 1;
				$connection_error = 4;
			}
			],

			[ qr/($enable_prompt)|($catos_enable_prompt)/,
			sub { 
				$spawn_ok = 1;
				$connection_error = 0;
				my $fh = shift;
				$fh -> send("\n");
				$self->{hostname} = $fh->matchlist()->[0];
			}
			]
		);
	} 

	if ( $connection_error == 0 && $spawn_ok == 1 ) {
		$self->{rExp} -> expect( 15,
			[ qr/(?i)error in authentication/,
			sub { 
				$spawn_ok = 1;
				$connection_error = 3;
			}
			],

			[ qr/(?i)invalid input detected/,
			sub {
				$spawn_ok = 1;
				$connection_error = 4;
			}
			],

			[ qr/($enable_prompt)|($catos_enable_prompt)/,
			sub {
				$spawn_ok = 1;
				$connection_error = 0;
				my $fh = shift;
				$self->{hostname} = $fh->matchlist()->[0];
			}
			],
		);
	}

	$self->{connection_error} = $connection_error;
	$self->{spawn_ok} = $spawn_ok;

	# If for some reason telnet did not spawn or login failed, we close the connection. 
	if ( $spawn_ok == 0 || $connection_error != 0 ) {
		$self->{rExp}->close();
	}
}

sub connectSSHv1
{
	my $self = shift;

	my $spawn_ok = 0;
	my $connection_error = 0; # 1 = auth fail, 2 = login loop

	$self->{rExp}->spawn("ssh -1 -l " . $self->{login} . " " . $self->{IP} . " 2>&1");

	my $user_prompt = '([^ \r\n]*)>';
	my $enable_prompt = '([^ \r\n]*)\#';
	my $config_global_prompt = '([^ \r\n]*).config.\#';
	my $config_line_prompt = '([^ \r\n]*).config-l\[ine]{0,3}.\#';
	my $config_interface_prompt = '([^ \r\n]*).config-(if?|s.*).\#';	
	my $config_acl_prompt = '([^ \r\n]*).config-\[^ \r\n]*\#';
	my $catos_enable_prompt = '([^ \r\n]*)> \(enable\)';
#	my $user_prompt = '[^ \r\n]*>';
#	my $enable_prompt = '[^ \r\n]*\#';
#	my $config_global_prompt = '[^ \r\n]*.config.\#';
#	my $config_line_prompt = '[^ \r\n]*.config-l\[ine]{0,3}.\#';
#	my $config_interface_prompt = '[^ \r\n]*.config-(if?|s.*).\#';	
#	my $config_acl_prompt = '[^ \r\n]*.config-\[^ \r\n]*\#';
#	my $catos_enable_prompt = '[^ \r\n]*> \(enable\)';

	$self->{current_connection_method} = "SSHv1";

	$self->{rExp} -> expect( 15, [ timeout => sub { $spawn_ok = 0; $connection_error = 0; } ],
		[ qr/\(yes\/no\)/,
		sub {
			$spawn_ok = 1;
			$connection_error = 0;
			my $fh = shift;
			$fh -> send("yes\n");
			exp_continue;
		}
		],

		[ qr/(?i)invalid input detected/,
		sub {
			$spawn_ok = 1;
			$connection_error = 4;
		}
		],

		[ qr/(?i)connection timed out/,
		sub {
			$spawn_ok = 0;
			$connection_error = 0;
		}
		],

		[ qr/(?i)not supported by server/,
                sub {
                        $spawn_ok = 0;
                        $connection_error = 0;
                }
                ],

		[ qr/(?i)Protocol major versions differ: 1 vs. 2/,
		sub {
			$spawn_ok = 0;
		}
		],

		[ qr/(?i)password:/,
		sub {
			$spawn_ok = 1;
			$connection_error = 0;
			my $fh = shift;
			$fh -> send($self->{pwd1} . "\n");
			exp_continue;
		}
		],

		[ qr/($user_prompt)/,
		sub {
			$spawn_ok = 1;
			$connection_error = 0;
			my $fh = shift;
			$fh -> send("ena\n");
			$self->{hostname} = $fh->matchlist()->[0];
		}
		],

		[ qr/($enable_prompt)|($catos_enable_prompt)/,
		sub {
			$spawn_ok = 1;
			$connection_error = 0;
			my $fh = shift;
			$fh -> send("\n");
			$self->{hostname} = $fh->matchlist()->[0];
		}
		],

		[ qr/(?i)Permission denied/,
		sub {
			$spawn_ok = 1;
			$connection_error = 1;
		}
		]
	);

	if ( $spawn_ok == 1 && $connection_error == 0 ) {
		$self->{rExp} -> expect( 15, [ timeout => sub { $spawn_ok = 1; $connection_error = 1; } ],
			[ qr/(?i)password:/,
			sub {
				$spawn_ok = 1;
				$connection_error = 0;
				my $fh = shift;
				$fh -> send($self->{pwd2} . "\n");
			}
			],

			[ qr/($enable_prompt)|($catos_enable_prompt)/,
			sub {
				$spawn_ok = 1;
				$connection_error = 0;
				my $fh = shift;
				$fh -> send("\n");
				$self->{hostname} = $fh->matchlist()->[0];
			}
			]
		);
	}

	if ( $spawn_ok == 1 && $connection_error == 0 ) {
		$self->{rExp} -> expect( 15,
			[ timeout => sub { $spawn_ok = 1; $connection_error = 1; } ],

			[ qr/(?i)error in authentication/,
			sub { 
				$spawn_ok = 1;
				$connection_error = 3;
			}
			],

			[ qr/($enable_prompt)|($catos_enable_prompt)/,
			sub {
				$spawn_ok = 1;
				$connection_error = 0;
				my $fh = shift;
				$fh -> send("\n");
				$self->{hostname} = $fh->matchlist()->[0];
			}
			]
		);
	}



	$self->{spawn_ok} = $spawn_ok;
	$self->{connection_error} = $connection_error;
	if ( $spawn_ok == 0 || $connection_error != 0 ) {
		$self->{rExp}->close();
	}
	#print "spawn_ok = " . $spawn_ok . "\n";
}

sub connectSSHv2
{
	my $self = shift;

	my $spawn_ok = 0;
	my $connection_error = 0; # 1 = auth fail, 2 = login loop

	$self->{rExp}->spawn("ssh -l " . $self->{login} . " " . $self->{IP} . " 2>&1");

	my $user_prompt = '([^ \r\n]*)>';
	my $enable_prompt = '([^ \r\n]*)\#';
	my $config_global_prompt = '([^ \r\n]*).config.\#';
	my $config_line_prompt = '([^ \r\n]*).config-l\[ine]{0,3}.\#';
	my $config_interface_prompt = '([^ \r\n]*).config-(if?|s.*).\#';	
	my $config_acl_prompt = '([^ \r\n]*).config-\[^ \r\n]*\#';
	my $catos_enable_prompt = '([^ \r\n]*)> \(enable\)';

	$self->{current_connection_method} = "SSHv2";

	$self->{rExp} -> expect( 15, [ timeout => sub { $spawn_ok = 0; $connection_error = 0; } ],
		[ qr/\(yes\/no\)/,
		sub {
			$spawn_ok = 1;
			$connection_error = 0;
			my $fh = shift;
			$fh -> send("yes\n");
			exp_continue;
		}
		],

		[ qr/(?i)invalid input detected/,
		sub {
			$spawn_ok = 1;
			$connection_error = 3;
		}
		],

		[ qr/(?i)connection timed out/,
		sub {
			$spawn_ok = 0;
			$connection_error = 0;
		}
		],

		[ qr/(?i)Protocol major versions differ: 1 vs. 2/,
		sub {
			$spawn_ok = 0;
		}
		],

#               In case of a menu with Selection, make sure the command is 0 to jump out of the menu
		[ qr/(?i)Selection:/,
                sub {
                        $spawn_ok = 1;
                        $connection_error = 0;
                        my $fh = shift;
                        $fh -> send("0\n");
                        exp_continue;
                }
                ],

		[ qr/(?i)password:/,
		sub {
			$spawn_ok = 1;
			$connection_error = 0;
			my $fh = shift;
			$fh -> send($self->{pwd1} . "\n");
			exp_continue;
		}
		],

		[ qr/$user_prompt/,
		sub {
			$spawn_ok = 1;
			$connection_error = 0;
			my $fh = shift;
			$fh -> send("ena\n");
			$self->{hostname} = $fh->matchlist()->[0];
		}
		],

		[ qr/$enable_prompt|$catos_enable_prompt/,
		sub {
			$spawn_ok = 1;
			$connection_error = 0;
			my $fh = shift;
			$fh -> send("\n");
			$self->{hostname} = $fh->matchlist()->[0];
		}
		],

		[ qr/RSA modulus too small: 512 < minimum 768 bits/,
		sub { 
			$spawn_ok = 0;
			$connection_error = 0;
			$self->{ssh_key_to_short} = 1;
		}
		],

		[ qr/(?i)Permission denied/,
		sub {
			$spawn_ok = 1;
			$connection_error = 1;
		}
		]
	);

	if ( $spawn_ok == 1 && $connection_error == 0 ) {
		$self->{rExp} -> expect( 15, [ timeout => sub { $spawn_ok = 1; $connection_error = 1; } ],
			[ qr/(?i)password:/,
			sub {
				$spawn_ok = 1;
				$connection_error = 0;
				my $fh = shift;
				$fh -> send($self->{pwd2} . "\n");
			}
			],
			[ qr/(?i)Access denied/,
			sub {
				$spawn_ok = 1;
				$connection_error = 1;
			}
			],

			[ qr/$enable_prompt|$catos_enable_prompt/,
			sub {
				$spawn_ok = 1;
				$connection_error = 0;
				my $fh = shift;
				$fh -> send("\n");
				$self->{hostname} = $fh->matchlist()->[0];
			}
			]
		);
	}

	if ( $spawn_ok == 1 && $connection_error == 0 ) {
		$self->{rExp} -> expect( 15,
			[ timeout => sub { $spawn_ok = 1; $connection_error = 1; } ],

			[ qr/(?i)error in authentication/,
			sub { 
				$spawn_ok = 1;
				$connection_error = 3;
			}
			],

			[ qr/$enable_prompt|$catos_enable_prompt/,
			sub {
				$spawn_ok = 1;
				$connection_error = 0;
				my $fh = shift;
				$fh -> send("\n");
				$self->{hostname} = $fh->matchlist()->[0];
			}
			]
		);
	}



	$self->{spawn_ok} = $spawn_ok;
	$self->{connection_error} = $connection_error;
	if ( $spawn_ok == 0 || $connection_error != 0 ) {
		$self->{rExp}->close();
	}
	#print "spawn_ok = " . $spawn_ok . "\n";
}


#sub DoExecute
#{
##	my $command = "@_[0]";
##	my $logFile = "@_[1]";
#	my $self = shift;
# 	my $commands = shift;
#
#	my $user_prompt = '[^ \r\n]*>';
#	my $enable_prompt = '[^ \r\n]*\#';
#	my $config_global_prompt = '[^ \r\n]*.config.\#';
#	my $config_line_prompt = '[^ \r\n]*.config-l\[ine]{0,3}.\#';
#	my $config_interface_prompt = '[^ \r\n]*.config-(if?|s.*).\#';
#	my $config_acl_prompt = '[^ \r\n]*.config-\[^ \r\n]*\#';
#	my $catos_enable_prompt = '[^ \r\n]*> \(enable\)';
#
#	$self->{rExp} -> restart_timeout_upon_receive(1);
##	$self->{rExp} -> log_file($logFile);
#	$self->{rExp} -> log_stdout(1);
#
#	$self->{rExp} -> send("\n");
# 	foreach my $command ( @{$commands} ) {
#		if ( $command =~ /^\s*$/ ) { $command = ""; }
#		$self->{rExp} -> expect( 90,
#				[ qr/\?/,
#				  sub {
#					  my $fh = shift;
#					  $fh -> send($command . "\n");
#				  } ], 
#				[ qr/$user_prompt|$enable_prompt|$config_global_prompt|$config_line_prompt|$config_interface_prompt|$config_acl_prompt|$catos_enable_prompt/,
#				  sub {
#				    my $fh = shift;
#				    $fh -> send($command . "\n");
#				  } ],
#				[ 'timeout',
#				  sub {
#					print "TIMEOUT\n\n"
#				  }
#				]
#				);
# 	}
#}

sub DoExecute
{
#	my $command = "@_[0]";
#	my $logFile = "@_[1]";
	my $self = shift;
	my $commands = shift;

	my $user_prompt = '[^ \r\n]*>';
	my $enable_prompt = '[^ \r\n]*\#';
	my $config_global_prompt = '[^ \r\n]*.config.\#';
	my $config_line_prompt = '[^ \r\n]*.config-l\[ine]{0,3}.\#';
	my $config_interface_prompt = '[^ \r\n]*.config-(if?|s.*).\#';
	my $config_acl_prompt = '[^ \r\n]*.config-\[^ \r\n]*\#';
	my $catos_enable_prompt = '[^ \r\n]*> \(enable\)';

	$self->{rExp} -> restart_timeout_upon_receive(1);
	$self->{rExp} -> log_stdout(1);

	$self->{rExp} -> send("\n");
	my $previous_command = "";
	$self->{commands_had_errors} = 0;
	foreach my $command ( @{$commands} ) {
		if ( $command =~ /^\s*$/ ) { $command = ""; }

		$self->{rExp} -> expect( 90,
			# If an error occurs (a line starting with '%') then remember the command which caused the error, and the error.	

			[ qr/\%\s*([^\r\n]*)/,
			sub {
				my $fh = shift;
				$self->{commands_had_errors} = 1;
				push @{$self->{error_commands}}, $previous_command;
				push @{$self->{error_lines}}, $fh->matchlist()->[0];
				#$fh -> send("\n");
				exp_continue;
			}
			],
			# Some commands generate additional questions (lines ending on a '?'). These lines also cause to send the next command.
			[ qr/\?/,
			sub {
				my $fh = shift;
				$fh -> send($command . "\n");
			} 
			],
			# When a prompt is encountered, send the next command.
			[ qr/$user_prompt|$enable_prompt|$config_global_prompt|$config_line_prompt|$config_interface_prompt|$config_acl_prompt|$catos_enable_prompt/,
			sub {
				my $fh = shift;
				$fh -> send($command . "\n");
			} 
			],
		);

		if ( $command ne "" ) { 
			$previous_command = $command;
		}
	}
	### After last command, we still have to check if an error occured.
	$self->{rExp} -> expect( 90,
		# If an error occurs (a line starting with '%') then remember the command which caused the error, and the error.	
		[ qr/\%\s*([^\r\n]*)/,
		sub {
			my $fh = shift;
			$self->{commands_had_errors} = 1;
			push @{$self->{error_commands}}, $previous_command;
			push @{$self->{error_lines}}, $fh->matchlist()->[0];
			$fh -> send("\n");
			exp_continue;
		}
		],
		# When a prompt is encountered, send the next command.
		[ qr/$user_prompt|$enable_prompt|$config_global_prompt|$config_line_prompt|$config_interface_prompt|$config_acl_prompt|$catos_enable_prompt/,
		sub {
		} 
		],
	);
}


sub DoCopyConfigToTFTP
{
	my $self = shift;
	my $tftpserver = shift;
	my $filename = shift || "";

	if ( $filename eq "" ) { 
		# if no filename is given, the filename to store the config in is <HOSTNAME>_<TIMESTAMP>
		my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime(time);
		my $timestamp = sprintf( "%4d%02d%02d%02d%02d%02d", $year + 1900, $mon + 1, $mday, $hour, $min, $sec );
		$filename = $self->{hostname} . "_" . $timestamp . "-confg";
	}

	my $user_prompt = '[^ \r\n]*>';
	my $enable_prompt = '[^ \r\n]*\#';
	my $config_global_prompt = '[^ \r\n]*.config.\#';
	my $config_line_prompt = '[^ \r\n]*.config-l\[ine]{0,3}.\#';
	my $config_interface_prompt = '[^ \r\n]*.config-(if?|s.*).\#';
	my $config_acl_prompt = '[^ \r\n]*.config-\[^ \r\n]*\#';
	my $catos_enable_prompt = '[^ \r\n]*> \(enable\)';

	$self->{rExp} -> restart_timeout_upon_receive(1);
	$self->{rExp} -> log_stdout(1);

	my $type = "";

	$self->{rExp} -> send("\n");
	$self->{rExp} -> expect( 15, [ timeout => sub { } ],
		[ qr/$enable_prompt/,
		sub {
			$type = "IOS";
		} ],
		[ qr/$catos_enable_prompt/,
		sub {
			$type = "CATOS";
		} ],
	);

	if ( $type eq "IOS" ) {
		$self->DoExecute( ["copy run tftp://$tftpserver/$filename", "", "", ""] );
#		$self->{rExp} -> send("\n");
#		$self->{rExp} -> expect( 15, [ timeout => sub { } ],
#			[ qr/$enable_prompt/, 
#			sub {
#				my $fh = shift;
#				$fh -> send( "copy run tftp://$tftpserver/$filename\n" );
#			} ] 
#		);
#
#		$self->{rExp} -> expect( 15, [ timeout => sub { } ],
#			[ qr/\?/,
#			sub {
#				my $fh = shift;
#				$fh -> send("\n");
#				exp_continue;
#			} ],
#			[ qr/$enable_prompt/,
#			sub {
#				my $fh = shift;
#				$fh -> send("\n");
#			} ] 
#		);
	}
	 
	if ( $type eq "CATOS" ) {
		$self->{rExp}->send("write network all\n");
		$self->{rExp} -> expect( 15, [ timeout => sub { } ],
			[ qr/IP address or name of remote host/,
			sub {
				my $fh = shift;
				$fh->send("$tftpserver\n");
				exp_continue;
			} ],
			[ qr/Name of configuration file/,
			sub {
				my $fh = shift;
				$fh->send("$filename\n");
				exp_continue;
			} ],
			[ qr/Upload configuration to/,
			sub {
				my $fh = shift;
				$fh->send("y\n");
				exp_continue;
			} ],
			[ qr/$catos_enable_prompt/,
			sub {
				my $fh = shift;
				$fh->send("\n");
			} ]
		);
	}
}
		
sub DoExit
{
	my $self = shift;

	my $user_prompt = '[^ \r\n]*>';
	my $enable_prompt = '[^ \r\n]*\#';
	my $config_global_prompt = '[^ \r\n]*.config.\#';
	my $config_line_prompt = '[^ \r\n]*.config-l\[ine]{0,3}.\#';
	my $config_interface_prompt = '[^ \r\n]*.config-(if?|s.*).\#';
	my $config_acl_prompt = '[^ \r\n]*.config-\[^ \r\n]*\#';
	my $catos_enable_prompt = '[^ \r\n]*> \(enable\)';

	$self->{rExp} -> send ("\n");
	$self->{rExp} -> expect( 5, '-re', "$user_prompt|$enable_prompt|$config_global_prompt|$config_line_prompt|$config_interface_prompt|$config_acl_prompt|$catos_enable_prompt" );
	$self->{rExp} -> send ("exit\n");

	return 0;
}

sub StartInteract
{
	my $self = shift;

	if ( $self->{spawn_ok} == 1 && $self->{connection_error} == 0 ) {
		$self->{rExp} -> interact();
	}
}

sub GoodBye
{
	my $self = shift;
	$self->{rExp} -> soft_close();
}

sub PrintReport
{
	my $self = shift;
	my $returnInfo;
#	print "\n======================================================\n";
	print "\n";
	$returnInfo = "<HR>Report of connection to " . $self->{IP} . "\n\n";
#	for ( my $aaaa = 1; $aaaa <= length("Report of connection to " . $self->{IP}); $aaaa++ ) { print "-"; } print "\n";
	if ( $self->{hostname} ne "" ) { $returnInfo = $returnInfo . "Hostname: " . $self->{hostname} . "\n"; }
	$returnInfo = $returnInfo . "Login used: " . $self->{login} . "\n";
	$returnInfo = $returnInfo . "Spawn status: " . $self->{spawn_ok};
	$returnInfo = $returnInfo . " ( ";
	if (  $self->{spawn_ok} == 0 ) { $returnInfo = $returnInfo . "<B>No connection method is usable</B>"; } else {$returnInfo = $returnInfo . "Spawn was OK";}
	$returnInfo = $returnInfo . " )\n";
	$returnInfo = $returnInfo . "Connection error: " . $self->{connection_error};
	$returnInfo = $returnInfo . " ( ";
	if ( $self->{connection_error} == 0 ) { $returnInfo = $returnInfo . "No error" } elsif ( $self->{connection_error} == 1 ) { $returnInfo = $returnInfo . "<B>authentication failure (login)</B>" } elsif ($self->{connection_error} == 2) { $returnInfo = $returnInfo . "<B>login loops (aka device keeps on asking for username)</B>" } elsif ( $self->{connection_error} == 4 ) { $returnInfo = $returnInfo . "<B>invalid input detected (only after sending enable command)</B>"; }
	$returnInfo = $returnInfo . " )\n";
	$returnInfo = $returnInfo . "Connection method was: " . $self->{current_connection_method} . "\n";
	$returnInfo = $returnInfo . "Preferred connection method was: " . $self->{prefered_connection_method} . "\n";
	$returnInfo = $returnInfo . "Order of connection methods was: ";
	for my $aaaa (@{$self->{connection_method_order}}) { $returnInfo = $returnInfo . $aaaa . " " }
	print "\n";
	if ( $self->{ssh_key_to_short} == 1 ) { $returnInfo = $returnInfo . "SSH key on device is too short.\n"; }
	if ( defined($self->{error_commands}) && scalar( $self->{error_commands} ) > 0 ) { 
		$returnInfo = $returnInfo . "Some commands had errors:\n"; 
		my $counter = 0;
		for ( $counter = 0; $counter < scalar( @{$self->{error_lines}} ); $counter++ ) {
			$returnInfo = $returnInfo . "line '<B>" . $self->{error_commands}[$counter] . "</B>' had the error '<B>" . $self->{error_lines}[$counter] . "</B>'\n";
		}
	}
	$returnInfo = $returnInfo . "\n\n";
        # save the connection method.
        my $ipAddr = $self->{IP};
        my $devDir = getDevDir( $ipAddr );
        printFileLine("$devDir/loginMethod","quiet",$self->{current_connection_method});
	return $returnInfo;
}

sub DESTROY {
	my $self = shift;
	$self->{rExp} = undef;
}
1;
